package com.xlh.service.conclude.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import com.xlh.common.ResultEnum;
import com.xlh.constant.ConcludeContant;
import com.xlh.dao.conclude.ext.ConcludeScoreMapperExt;
import com.xlh.dao.conclude.helper.*;
import com.xlh.dto.conclude.CourseStudentStatisticDTO;
import com.xlh.exception.common.GlobalException;
import com.xlh.pojo.conclude.*;
import com.xlh.service.conclude.ConcludeStatisticsService;
import com.xlh.util.BeanUtil;
import com.xlh.vo.conclude.CourseStatisticVO;
import com.xlh.vo.conclude.CourseStudentStatisticVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static cn.hutool.core.util.NumberUtil.*;

@Service
public class ConcludeStatisticsServiceImpl implements ConcludeStatisticsService {

    @Autowired
    private ConcludeCourseMapperHelper concludeCourseMapperHelper;

    @Autowired
    private ConcludeSubCourseMapperHelper concludeSubCourseMapperHelper;

    @Autowired
    private ConcludeScoreMapperHelper concludeScoreMapperHelper;

    @Autowired
    private ConcludeCheckSubMapperHelper concludeCheckSubMapperHelper;

    @Autowired
    private ConcludeCheckMapperHelper concludeCheckMapperHelper;

    @Autowired
    private ConcludeMapperHelper concludeMapperHelper;

    @Autowired
    private ConcludeStudentMapperHelper concludeStudentMapperHelper;

    @Autowired
    private ConcludeScoreMapperExt concludeScoreMapperExt;


    @Override
    public List<CourseStatisticVO> statisticsCourse(Long concludeId) {

        // 验证参数
        if(ObjectUtil.isNull(concludeId)){
            throw new GlobalException(ResultEnum.BAD_REQUEST);
        }
        Conclude conclude = concludeMapperHelper.get(concludeId);
        if(ObjectUtil.isNull(conclude)){
            throw new GlobalException(ResultEnum.NOT_FOUND_CONCLUDE);
        }

        BigDecimal thresholdValue = div(conclude.getThresholdValue(), 100, 2); // 阈值
        List<ConcludeCourse> concludeCourses = concludeCourseMapperHelper.findByCondition(concludeId);
        List<Long> courseIds = concludeCourses.stream().map(ConcludeCourse::getId).collect(Collectors.toList());
        // 未创建关联的课程
        if(CollectionUtil.isEmpty(courseIds)){

            return null;
        }
        // 未查询到当前关联的学生
        List<ConcludeStudent> concludeStudents = concludeStudentMapperHelper.findByCondition(concludeId,null);
        List<String> snoInfo = concludeStudents.stream().map(ConcludeStudent::getSno).collect(Collectors.toList());
        if(CollectionUtil.isEmpty(snoInfo)){
            return null;
        }

        // 未关联考核分项
        List<ConcludeSubCourse>  concludeSubCourses = concludeSubCourseMapperHelper.findByCourseId(courseIds);
        if(CollectionUtil.isEmpty(concludeSubCourses)){
            return null;
        }
        Map<Long, List<ConcludeSubCourse>> courseIdMap = concludeSubCourses.stream().collect(Collectors.groupingBy(ConcludeSubCourse::getConCourseId));
        Map<String, List<ConcludeStudent>> snoMap = concludeStudents.stream().collect(Collectors.groupingBy(ConcludeStudent::getSno));
        List<CourseStatisticVO> result = Lists.newArrayList();

        // 获取课程目标
        for (ConcludeCourse concludeCours : concludeCourses) {

            // 课程权重为空 返回
            Long courseId = concludeCours.getId();
            // 获取关联的学生及成绩

            List<BigDecimal> courseThresholdList = Lists.newArrayList(); // 阈值得分集合
            List<BigDecimal> scoreList = Lists.newArrayList(); // 得分集合
            Map<String, BigDecimal> snoMapScore = new HashMap<>(); // 学号， 成绩比
            List<ConcludeSubCourse> courseIdSubInfo = courseIdMap.get(courseId);

            if(CollectionUtil.isEmpty(courseIdSubInfo)){

                CourseStatisticVO courseStatisticVO = new CourseStatisticVO();
                courseStatisticVO.setProportion(new BigDecimal(0));
                courseStatisticVO.setData(Lists.newArrayList());
                result.add(courseStatisticVO);
                // 未关联考核项
                continue;
            }

            for (ConcludeSubCourse concludeSubCourse : courseIdSubInfo) {

                double courseWeight = NumberUtil.div(concludeSubCourse.getCourseWeight().doubleValue(), 100d);// 课程权重
                Long checkSubId = concludeSubCourse.getCheckSubId();        // 考核分项

                ConcludeCheckSub concludeCheckSub = concludeCheckSubMapperHelper.get(checkSubId);
                if(concludeCheckSub == null){
                    continue;
                }
                if(ObjectUtil.isNull(concludeCheckSub.getFullMark())){
                    concludeCheckSub.setFullMark(new BigDecimal(100));
                }
                ConcludeCheck concludeCheck = concludeCheckMapperHelper.getById(concludeCheckSub.getCheckId());
                if(ObjectUtil.isNull(concludeCheck.getWeight())){
                    continue;
                }

                BigDecimal checkWeight = div(concludeCheck.getWeight(), 100, ConcludeContant.RETAIN_DECIMALS);  // 考核项权重
                BigDecimal subWeight = div(concludeCheckSub.getWeight(), 100, ConcludeContant.RETAIN_DECIMALS);  // 考核分项权重

                // 阈值的List
                BigDecimal courseThreshold = mul( checkWeight ,  courseWeight, subWeight,  thresholdValue, 100);
                courseThresholdList.add(courseThreshold);

                // 查询学生的平均成绩 * 考核分项比例 *
                BigDecimal avgScore = concludeScoreMapperExt.getAvgScore(concludeCheckSub.getId(), concludeId);
                if(ObjectUtil.isNull(avgScore)){
                    continue;
                }
                BigDecimal subFullMark = div(avgScore, concludeCheckSub.getFullMark());
                BigDecimal courseScore = mul( checkWeight , mul( subFullMark, 100 ), courseWeight, subWeight );
                // 得分List

                scoreList.add(courseScore);

                // 查询下面的学生
                List<ConcludeScore> concludeScores = concludeScoreMapperHelper.findCheckSubScoreBySubId(checkSubId, snoInfo);

                if(CollectionUtil.isEmpty(concludeScores)){
                    continue;
                }
                // 每个学生获取的课程一的分数
                for (ConcludeScore concludeScore : concludeScores) {
                    // 学生分数
                    BigDecimal fullMark = new BigDecimal(100);
                    if(ObjectUtil.isNotNull(concludeCheckSub.getFullMark())){
                        fullMark = concludeCheckSub.getFullMark();
                    }
                    BigDecimal studentSubScore = mul(div(concludeScore.getScore(), fullMark), 100) ;
                    String studentNo = concludeScore.getStudentNo();
                    BigDecimal subScore = mul(studentSubScore, subWeight, checkWeight, courseWeight);
                    BigDecimal accumulation = snoMapScore.get(studentNo);
                    if(ObjectUtil.isNull(accumulation)){
                        accumulation =  subScore;
                    }else{
                        accumulation = add(subScore, accumulation);
                    }
                    snoMapScore.put(studentNo, accumulation);
                }
            }
            //计算阈值和平均值的比重
            Optional<BigDecimal> scoreCount = scoreList.stream().reduce(NumberUtil::add);
            if(!scoreCount.isPresent()){
                // 未找到学生成绩
                CourseStatisticVO courseStatisticVO = new CourseStatisticVO();
                courseStatisticVO.setProportion(new BigDecimal(0));
                courseStatisticVO.setData(Lists.newArrayList());
                result.add(courseStatisticVO);
                continue;
            }

            Optional<BigDecimal> thresholdCount = courseThresholdList.stream().reduce(NumberUtil::add);

            CourseStatisticVO courseStatisticVO = new CourseStatisticVO();
            List<CourseStudentStatisticVO> studentInfo = Lists.newArrayList();
            courseStatisticVO.setData(studentInfo);
            BigDecimal thresholdCountBigD = thresholdCount.orElse(new BigDecimal("0"));

            BigDecimal proportion = div(scoreCount.orElse(new BigDecimal("0")), thresholdCountBigD);
            courseStatisticVO.setProportion(round(proportion, 2));

            // 计算学生的整体成绩比例
            Set<String> snoNumbers = snoMapScore.keySet();
            int index = 1;
            for (String snoNumber : snoNumbers) {

                if(ObjectUtil.isNull(snoMap.get(snoNumber))){
                    continue;
                }
                ConcludeStudent concludeStudent = snoMap.get(snoNumber).get(0);
                BigDecimal studentScoreCount = snoMapScore.get(snoNumber);
                BigDecimal studentProportion = div(studentScoreCount, thresholdCountBigD);

                // 装在结果
                CourseStudentStatisticVO courseStudentStatisticVO = new CourseStudentStatisticVO();
                courseStudentStatisticVO.setName(concludeStudent.getName());
                courseStudentStatisticVO.setOrderNo(index++);
                courseStudentStatisticVO.setProportion(studentProportion);
                studentInfo.add(courseStudentStatisticVO);
            }
            result.add(courseStatisticVO);
        }

        return result;
    }

    @Override
    public List<List<Integer>> studentCount(Long concludeId) {


        List<ConcludeCourse> concludeCourses = concludeCourseMapperHelper.findByCondition(concludeId);
        List<Long> courseIds = concludeCourses.stream().map(ConcludeCourse::getId).collect(Collectors.toList());

        List<ConcludeStudent> students = concludeStudentMapperHelper.findByCondition(concludeId, null);
        List<String> snos = students.stream().map(ConcludeStudent::getSno).collect(Collectors.toList());

        if(CollectionUtil.isEmpty(snos)){
            return null;
        }
        if(CollectionUtil.isEmpty(courseIds)){
            return null;
        }
        List<ConcludeSubCourse>  concludeSubCourses = concludeSubCourseMapperHelper.findByCourseId(courseIds);
        if(CollectionUtil.isEmpty(concludeCourses)){
            return null;
        }
        Map<Long, List<ConcludeSubCourse>> subCourseByCourseId = concludeSubCourses.stream().collect(Collectors.groupingBy(ConcludeSubCourse::getConCourseId));

        // 获取所有的subId及学生
        // 2. 获取关联的所有考核分项
        List<Map<String, BigDecimal>> lists = Lists.newArrayList();

        for (ConcludeCourse concludeCours : concludeCourses) {

            Long courseId = concludeCours.getId();
            // 课程权重值
            Double courseWeight = div(Double.valueOf(concludeCours.getWeight()), Double.valueOf(100d), 2);
            // 3. 获取关联的学生及成绩
            List<ConcludeSubCourse> courseIdSubInfo = subCourseByCourseId.get(courseId);
            // 4. 查询学生ID下的成绩
            // 学号， 成绩比
            Map<String, BigDecimal> snoMapScore = new HashMap<>();
            for (ConcludeSubCourse concludeSubCourse : courseIdSubInfo) {

                Long checkSubId = concludeSubCourse.getCheckSubId();
                ConcludeCheckSub concludeCheckSub = concludeCheckSubMapperHelper.get(checkSubId);
                BigDecimal subWeight = div(concludeCheckSub.getWeight(), 100, ConcludeContant.RETAIN_DECIMALS);  // 考核分项权重
                // 查询学生的平均成绩 * 考核分项比例 *
                // 查询下面的学生
                List<ConcludeScore> concludeScores = concludeScoreMapperHelper.findCheckSubScoreBySubId(checkSubId, snos);

                for (ConcludeScore concludeScore : concludeScores) {
                    // 学生分数
                    BigDecimal studentSubScore = concludeScore.getScore();
                    String studentNo = concludeScore.getStudentNo();
                    BigDecimal subScore = mul(studentSubScore, subWeight, courseWeight);
                    BigDecimal accumulation = snoMapScore.get(studentNo);
                    if(ObjectUtil.isNull(accumulation)){
                        accumulation =  subScore;
                    }else{
                        // 进行成绩累加
                        accumulation = add(subScore, accumulation);
                    }
                    snoMapScore.put(studentNo, accumulation);
                }
            }
            lists.add(snoMapScore);
        }

        List<List<Integer>> result = Lists.newArrayList();
        List<Predicate<BigDecimal>> stageList = initStageList();

        // 表示6个阶段
        for (int i = 0; i < stageList.size() ; i++) {

            Predicate<BigDecimal> predition = stageList.get(i);
            List<Integer> courseStuNumber = Lists.newArrayList();
            //对结果进行处理
            for (int j = 0; j <lists.size(); j++) {

                Map<String, BigDecimal> studentScore = lists.get(j);
                long count = studentScore.values().stream().filter(predition).count(); // 分数段学生人数
                courseStuNumber.add(((int) (count)));
            }
            result.add(courseStuNumber);
        }

        return result;
    }


    /**
     * 初始化阶段性人数
     * @return
     */
    private List<Predicate<BigDecimal>> initStageList() {

        // '50~59分', '60~69分', '70~79分', '80~89分', '90~99分', '100分
        Predicate<BigDecimal> stageOne = bigd -> 50<bigd.intValue()&& bigd.intValue()<=59;
        Predicate<BigDecimal> stageTwo = bigd -> 60<bigd.intValue()&& bigd.intValue()<=69;
        Predicate<BigDecimal> stageThree = bigd -> 70<bigd.intValue()&& bigd.intValue()<=79;
        Predicate<BigDecimal> stageFour = bigd -> 80<bigd.intValue()&& bigd.intValue()<=89;
        Predicate<BigDecimal> stageFive = bigd -> 90<bigd.intValue()&& bigd.intValue()<=99;
        Predicate<BigDecimal> stageSix = bigd -> bigd.intValue()==100;

        List<Predicate<BigDecimal>> listStage = Lists.newArrayList();
        listStage.add(stageOne);
        listStage.add(stageTwo);
        listStage.add(stageThree);
        listStage.add(stageFour);
        listStage.add(stageFive);
        listStage.add(stageSix);

        return listStage ;
    }
}
